package org.colcon.web.server;

import java.util.Map;

import org.colcon.web.model.framework.IBallot;
import org.colcon.web.model.framework.ICommand;
import org.colcon.web.model.framework.IContainer;
import org.colcon.web.model.framework.IItem;
import org.colcon.web.model.framework.IVote;
import org.colcon.web.model.parsers.CLIParser;

public class CLI 
{
	public static final String
		
		DELIMETER = " ",
		ARG_TAG = "-",
	
		USERS = "users",
		GROUPS = "groups",
		
		// groups
		CONTRIBUTOR_CONGRESS = "contributor_congress",
		GROUP_CONGRESS = "group_congress",
		USER_CONGRESS = "user_congress",
		
		// users
		ADMIN = "admin",
		
		// commands
		NULL = "null",
		HELP = "colcon/commands/help",
		PRINT = "colcon/commands/print",
		GET = "colcon/commands/get",
		SET = "colcon/commands/set",
		ADD = "colcon/commands/add",
		REMOVE = "colcon/commands/remove",
		OPEN = "colcon/commands/open",
		RESOLVE = "colcon/commands/resolve",
		LOAD = "colcon/commands/load",
		
		// command arguments
		CMD = "cmd",
		PATH = "path",
		TEXT = "text",
		ITEM = "item",
		TYPE = "type",
		NEXT = "next",
		ARG = "arg",
		LONG = "long";
	
	public static String execute(String command)
	{
		command = command.trim();
		
		while(command.startsWith(";"))
			command = command.substring(0);
		
		while(command.endsWith(";"))
			command = command.substring(0, command.length() - 1);
		
		command = command.trim();
		
		String output = "";
		
		String[] array = command.split(";");
		
		if(array.length > 1)
		{
			for(String str : array)
			{
				str = str.trim();
				if(str.length() > 0)
					output += execute(str) + "\n";
			}
			
			output = output.trim();
			
			return output;
		}
		else
		{
			String cmd = CLIParser.parseCmd(command);
			
			if(cmd == null || cmd.trim().length() == 0)
				return "missing command";
			
			if(!Model.hasCommand(cmd))
				return "command '" + cmd + "' not found";
			
			Model.logCommand(command);
		
			return execute(CLIParser.parseCommand(command));
		}
	}
	
	public static String execute(Map<String, String> args)
	{
		if(args.containsKey(NEXT))
		{
			String next = args.remove(NEXT);
			return execute(args) + '\n' + execute(next);
		}
		
		String cmd = args.get(CMD);
		
		if(cmd.equals(NULL))
		{
			return NULL;
		}
		else if(cmd.equals(HELP))
		{
			return getHelpString();
		}
		else if(cmd.equals(PRINT))
		{
			String text = args.get(TEXT);
			
			if(text == null)
				return NULL;
			
			return text;
		}
		else if(cmd.equals(GET))
		{
			String path = args.get(PATH);
			
			if(path == null)
				return "missing path";
			
			if(!Model.has(path))
				return "item '" + path + "' not found";
			
			IItem item = Model.get(path);
			
			if(args.containsKey(ARG))
				return item.getArg(args.get(ARG));
			
			return item.toString();
		}
		else if(cmd.equals(OPEN))
		{
			String path = args.get(PATH);
			
			if(path == null)
				return "missing path";
			
			if(!Model.has(path))
				return "item '" + path + "' not found";
			
			IItem item = Model.get(path);
			
			if(!(item instanceof IContainer))
				return "item '" + path + "' is not a container";
			
			String output = item.getText() + "\n\n";
			
			IItem[] children = Model.open(path);
			
			for(int i = 0; i < children.length; i++)
				output += String.format("%1$-" + 5 + "s", i) + children[i].getText() + "\n";
			
			if(children.length == 0)
				output += "     container is empty";
			
			return output;
		}
		else if(cmd.equals(ADD))
		{
			String path = args.get(PATH);
			
			if(path == null)
				return "missing path";
			
			if(!Model.has(path))
				return "container '" + path + "' not found";
			
			if(!(Model.get(path) instanceof IContainer))
				return "item " + path + " is not a container";
			
			IItem item = CLIParser.parseItem(args.get(ITEM));
			
			if(item == null)
				return "invalid item";
			
			if(Model.has(item.getPath()))
				return "item " + item.getId() + " already exists in " + path;
			
			Model.add(item);

			return "item " + item.getId() + " successfully added to " + path;
		}
		else if(cmd.equals(REMOVE))
		{
			String path = args.get(PATH);
			
			if(path == null)
				return "missing path";
			
			if(!Model.has(path))
				return "item " + path + " not found";
			
			boolean result = Model.remove(path);
			
			if(!result)
				return "failed to remove item " + path;
			
			return "item " + path + " successfully removed";
		}
		else if(cmd.equals(RESOLVE))
		{
			String path = args.get(PATH);

			if(!Model.has(path))
				return "item '" + path + "' not found";
			
			IItem item = Model.get(path);
			
			if(!(item instanceof IVote))
				return "item '" + path + "' is not a vote";
			
			IVote vote = (IVote) item;
			
			Model.remove(path);
			
			IItem[] items = Model.open(vote.ballots());
			
			if(items == null)
				return "container '" + vote.ballots() + "' not found";
			
			IBallot[] ballots = new IBallot[items.length];
			
			for(int i = 0; i < ballots.length; i++)
				if(items[i] instanceof IBallot)
					ballots[i] = (IBallot) items[i];
			
			
			return execute(vote.getResult((IBallot[]) ballots));
		}
		else
		{
			if(!Model.hasCommand(cmd))
				return "command '" + cmd + "' not found";
			
			ICommand command = (ICommand) Model.getCommand(cmd);
			
			String next = command.getCommand(args);
			
			if(CLIParser.parseCmd(next).equals(cmd))
				return NULL;
			
			return execute(next);
		}
	}
	
	public static String getHelpString()
	{
		String str = "";
		
		for(ICommand command : Model.getCommands())
		{
			str += command.getId();
			
			for(String arg : command.getArgs())
				str += " -" + arg + " [" + arg + "]";
			
			str += '\n';
		}
		
		return str;
	}
}
